﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using Elte.SqlSpIdx;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Data;
namespace Elte.SqlSpIdx
{
    public static class Core
    {
        public static Elte.SqlSpIdx.Indices.Cache<string, Index> IndexCache = new Elte.SqlSpIdx.Indices.Cache<string, Index>();


        public static void CreateindexDetailed(string type, string name, string description, string table, string primaryKeyColumn, string indexColumn, string dataColumn, string dataColumnNames, string options)
        {
            try
            {

                using (SqlConnection cn = new SqlConnection(Constants.MyConnectionString))
                {
                    cn.Open();
                    if (type.ToString().ToLower().Contains("kdtree"))
                    {
                        Indices.BalancedTreeIndex I = new Elte.SqlSpIdx.Indices.BalancedTreeIndex(cn);
                        I.CreateIndex(name, description, table, primaryKeyColumn, indexColumn, dataColumn, dataColumnNames, options);
                    }
                    if (type.ToString().ToLower().Contains("grid"))
                    {
                        Indices.GridIndex I = new Elte.SqlSpIdx.Indices.GridIndex(cn);
                        I.CreateIndex(name, description, table, primaryKeyColumn, indexColumn, dataColumn, dataColumnNames, options);
                    }
                    Core.Log("Done.");
                }
            }
            catch (Exception ex)
            {
                Core.Log(ex.Message);
            }
        }

        public static void Createindex(string name, string table, string columns)
        {
            try
            {

                using (SqlConnection cn = new SqlConnection(Constants.MyConnectionString))
                {
                    cn.Open();
                    //defaul kd tree
                    Indices.BalancedTreeIndex I = new Elte.SqlSpIdx.Indices.BalancedTreeIndex(cn);
                    I.CreateIndex(name, null, table, null, null, null, columns, null);
                    Core.Log("Done.");
                }
            }
            catch (Exception ex)
            {
                Core.Log(ex.Message);
            }
        }

        public static IEnumerable<object[]> SpatialQueryGeneral(string selectlist, string tableorindex, string spatialwhere, string sqlwhere, bool callfromsqlfunction)
        {
            Index I = Core.GetSuitableIndex(tableorindex);
            I.DatabaseConnection = new SqlConnection(Constants.MyConnectionString);
            if (selectlist == null)
            {
                selectlist = I.PrimaryKeyColumn;
            }
            if (callfromsqlfunction)
            {
                List<object[]> result = new List<object[]>();
                IEnumerator<object[]> iresult = I.SpatialQuery(
                  selectlist,
                  spatialwhere,
                  sqlwhere).GetEnumerator();
                while (iresult.MoveNext())
                {
                    result.Add((object[])iresult.Current.Clone());
                }
                return result;
            }
            else
            {
                return I.SpatialQuery(
                    selectlist,
                    spatialwhere,
                    sqlwhere);
            }
        }


        public static void SpatialQuery(string selectlist, string tableorindex, string spatialwhere, string sqlwhere)
        {

            //Return structure
            SqlMetaData[] records;



            SqlDataRecord s = default(SqlDataRecord);

            IEnumerator<object[]> result = SpatialQueryGeneral((string)selectlist, (string)tableorindex, (string)spatialwhere, (string)sqlwhere,false).GetEnumerator();

            //Return values
            if (SqlContext.IsAvailable)
            {

                bool firstReturn = true;
                while (result.MoveNext())
                {
                    object[] values = result.Current;
                    if (firstReturn)
                    {
                        records = new SqlMetaData[values.Length];
                        for (int i = 0; i < values.Length; i++)
                        {
                            if (Common.GetDbType(values[i].GetType()) == SqlDbType.VarChar)
                            {

                                records[i] = new SqlMetaData(((string)selectlist).Split(',')[i], Common.GetDbType(values[i].GetType()), 128);
                            }
                            else
                            {
                                records[i] = new SqlMetaData(((string)selectlist).Split(',')[i], Common.GetDbType(values[i].GetType()));
                            }
                        }
                        s = new SqlDataRecord(records);
                        firstReturn = false;
                        SqlContext.Pipe.SendResultsStart(s);
                    }

                    s.SetValues(values);
                    SqlContext.Pipe.SendResultsRow(s);
                }
                if (!firstReturn) SqlContext.Pipe.SendResultsEnd();
            }
            else
            {

                while (result.MoveNext())
                {
                    object[] values = (object[])result.Current;
                    for (int i = 0; i < values.Length; i++)
                    {

                        Console.Write(values[i].ToString() + " ,");
                    }
                    Console.WriteLine();
                }
            }
        }


        public static void Log(string s)
        {
            if (SqlContext.IsAvailable)
            {
                SqlContext.Pipe.Send(s);
            }
            else
            {
                Console.WriteLine(s);
            }
        }
        public static string Spatial2sql(string spatialwhere, int dimension)
        {
            spatialwhere = spatialwhere.ToLower();
            string sqlwhere = "";
            string param;
            if (spatialwhere.StartsWith(@"distance("))
            {
                spatialwhere = spatialwhere.Remove(0, 9);
                for (int i = 0; i < dimension; i++)
                {
                    param = spatialwhere.Substring(0, spatialwhere.IndexOf("="));
                    spatialwhere = spatialwhere.Remove(0, spatialwhere.IndexOf("=") + 1);
                    param += "-(" + spatialwhere.Substring(0, spatialwhere.Contains(",") ? spatialwhere.IndexOf(",") : spatialwhere.IndexOf(@")")) + ")";
                    param = "((" + param + ")*(" + param + "))";
                    if (i != 0) sqlwhere += "+";
                    sqlwhere += param;
                    spatialwhere = spatialwhere.Remove(0, (spatialwhere.Contains(",") ? spatialwhere.IndexOf(",") : spatialwhere.IndexOf(@")")) + 1);


                }
                sqlwhere += spatialwhere.Substring(0, 1);
                spatialwhere = spatialwhere.Remove(0, 1);
                sqlwhere += spatialwhere + "*" + spatialwhere;
            }

            return sqlwhere;
        }
        public static Index GetSuitableIndex(string tableorindex)
        {
            SqlConnection cn = new SqlConnection(Constants.MyConnectionString);

            cn.Open();
            string chosenindexid = null;
            IndexType chosentype = IndexType.NoIndex;
            string sql = Elte.SqlSpIdx.Indices.IndexScripts.SelectPossibleIndexes;
            sql = sql.Replace("$id", tableorindex);
            using (SqlCommand cmd = new SqlCommand(sql, cn))
            {
                using (SqlDataReader rs = cmd.ExecuteReader())
                {
                    if (rs.Read())
                    {
                        chosenindexid = (string)rs["indexid"];
                        if ((string)rs["type"] == "NoIndex") chosentype = IndexType.NoIndex;
                        if ((string)rs["type"] == "BalancedTree") chosentype = IndexType.BalancedTree;
                        if ((string)rs["type"] == "Grid") chosentype = IndexType.Grid;
                    }
                    else
                    {
                        chosenindexid = tableorindex;
                        chosentype = IndexType.NoIndex;
                    }

                }

                //IndexType chosentype = IndexType.NoIndex;
                //switch (f)
                //{
                //    case IndexFunctionType.NN:
                //        chosentype = IndexType.BalancedTree;

                //        break;
                //    case IndexFunctionType.SpatialQuery:
                //        break;
                //    default:
                //        break;
                //}
            }
            Index I = Elte.SqlSpIdx.Index.LoadIndex(cn, chosenindexid, chosentype);
            cn.Close();

            return I;

        }
        public static Index GetSuitableIndex(SqlConnection cn, IndexFunctionType f, string tableorindex)
        {

            string chosenindexid = null;
            IndexType chosentype = IndexType.NoIndex;
            string sql = Elte.SqlSpIdx.Indices.IndexScripts.SelectPossibleIndexes;
            sql = sql.Replace("$id", tableorindex);
            using (SqlCommand cmd = new SqlCommand(sql, cn))
            {
                using (SqlDataReader rs = cmd.ExecuteReader())
                {
                    if (rs.Read())
                    {
                        chosenindexid = (string)rs["indexid"];
                        if ((string)rs["type"] == "NoIndex") chosentype = IndexType.NoIndex;
                        if ((string)rs["type"] == "BalancedTree") chosentype = IndexType.BalancedTree;
                        if ((string)rs["type"] == "Grid") chosentype = IndexType.Grid;
                    }
                    else
                    {
                        chosenindexid = tableorindex;
                        chosentype = IndexType.NoIndex;
                    }

                }
                //ha több lehetőség lesz..
                //IndexType chosentype = IndexType.NoIndex;
                //switch (f)
                //{
                //    case IndexFunctionType.NN:
                //        chosentype = IndexType.BalancedTree;

                //        break;
                //    case IndexFunctionType.SpatialQuery:
                //        break;
                //    default:
                //        break;
                //}
            }
            return Elte.SqlSpIdx.Index.LoadIndex(cn, chosenindexid, chosentype);
        }
    }
}
